package com.xiashitech.agent.rule.usermatch.base;

import com.xiashitech.agent.config.StartConfig;
import com.xiashitech.agent.dto.UserRequest;
import com.xiashitech.agent.instrumentation.base.context.TraceConst;
import com.xiashitech.agent.instrumentation.base.context.TraceContextVars;
import com.xiashitech.agent.service.ServiceRegister;
//import net.bytebuddy.description.type.TypeDescription;
//import net.bytebuddy.matcher.ElementMatchers;

import java.util.*;

public interface UserInfoMatchRule<REQUEST> extends Comparable<UserInfoMatchRule> {

    static <REQUEST> Optional<UserRequest> executeRule(REQUEST request) {
        List<UserInfoMatchRule> userInfoMatchRules = getRules();
        UserRequest userRequest = null;
        /**
         * 找到用户id，并记录请求时间，优先级高的规则先执行，找到就不在继续查找
         */
        for (UserInfoMatchRule userInfoMatchRule:userInfoMatchRules) {
            if(!userInfoMatchRule.isSuitable(request))
                continue;

            try {
                userRequest = userInfoMatchRule.extractUserInfo(request);
                if(userRequest != null && userRequest.getUserid() != null && userRequest.getRequestDate() != null && !"".equals(userRequest.getUserid()) && !"".equals(userRequest.getRequestDate())) {
                    break;
                }
            } catch (Throwable e) {
                StartConfig.throwableStackPrinter(e);
            }
        }
        /**
         * 执行所有规则并做用户信息的补充，优先级低的规则覆盖优先级高的规则
         */
        for (UserInfoMatchRule userInfoMatchRule:userInfoMatchRules) {
            try {
                userInfoMatchRule.postUserInfo(request,userRequest);
            } catch (Throwable e) {
                StartConfig.throwableStackPrinter(e);
            }
        }

        return Optional.ofNullable(userRequest);
    }

    /**
     * 规则的前置适配判断操作
     */
    default boolean isSuitable(REQUEST request){
        return true;
    }

    UserRequest extractUserInfo(REQUEST request);

    default void postUserInfo(REQUEST request, UserRequest userRequest) {

    }

    default void setUserId(UserRequest userRequest, String userId) {
        userRequest.setUserid(userId);
        TraceContextVars.get().set(TraceConst.XS_USER_ID, userId);
    }

    @Override
    default int compareTo(UserInfoMatchRule userInfoMatchRule) {
        return this.getOrder()-userInfoMatchRule.getOrder();
    }

    Integer getOrder();


    /** helper类中，可以使用bytebuddy包 **/
  /*  static boolean isPublic(Class<?> cls) {
        return ElementMatchers.isPublic().matches(TypeDescription.ForLoadedType.of(cls));
    }

    static boolean hasSuperType(Class<?> cls, String interfaceName) {
        return ElementMatchers.hasSuperType(ElementMatchers.named(interfaceName)).matches(TypeDescription.ForLoadedType.of(cls));
    }

    static boolean isType(Class<?> cls, String className) {
        return ElementMatchers.named(className).matches(TypeDescription.ForLoadedType.of(cls));
    }*/


    List<UserInfoMatchRule> rules = new ArrayList();

    static List<UserInfoMatchRule> getRules() {
        if (rules.size() == 0) {
            synchronized (rules) {
                if(rules.size() == 0) {
                    ServiceRegister<UserInfoMatchRule> register = new ServiceRegister<>(UserInfoMatchRule.class, "com.xiashitech.agent.rule.usermatch.inst");
                    List<UserInfoMatchRule> list = new ArrayList<>(register.getServices());
                    Collections.sort(list);
                    rules.addAll(list);
                }
            }
        }
        return rules;
    }

}
